/*
 * sgc_chat_logic_flash.c
 *
 *  Created on: 2011-7-12
 *      Author: rendong
 */
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "sgc_chat_logic_flash.h"
#include "../os/sgc_epoll.h"

static void sgc_user_add_channel(char * channelname, sgc_chat_session_t * session);
static void send_msg_list_foreach_handler(void *elements, int index, void * data);

// 解析字符串
#define PARSE_STR(pmessage,pos,str_len, pstr) do{\
str_len = *(int *)(pmessage+(pos));\
if (str_len == 0){\
	sgc_log_debug("str_len is NULL\n");\
	return;\
}\
if ((pos) + PKG_LEN_SIZE + str_len > len){\
sgc_log_debug("string not enough\n");\
	return;\
}\
pstr = malloc(str_len+1);\
memset(pstr, 0, str_len+1);\
memcpy(pstr, pmessage + (pos) + PKG_LEN_SIZE, str_len);\
}while(0);


/**
 * 加入聊天频道
 */
static void sgc_user_add_channel(char * channelname, sgc_chat_session_t * session)
{
	char * name = malloc(strlen(channelname) + 1);
	memset(name, 0, strlen(channelname) + 1);
	strcpy(name, channelname);

	sgc_list_t *list = sgc_hash_get(sgc_all_channels, name);

	if (list == NULL){
		list = sgc_list_create();
		sgc_hash_put(sgc_all_channels, name, list);
	}

	sgc_list_push(session->channels, name);
	sgc_list_push(list, session);
}


// 发送频道信息
static void send_msg_list_foreach_handler(void *elements, int index, void * data)
{
	sgc_chat_session_t * session = elements;
	sgc_chat_message_t * message = data;
	int n;
	if (session->login_type == LOGIN_TYPE_USER)
	{
		if ( (n = writen(session->fd, message->message, message->len)) != message->len)
		{
			sgc_log_debug("write fail fd:%d,uid:%s,uname:%s %s(%d) errno:%d %s\n", session->fd, session->userid,session->username, __FILE__, __LINE__, errno, strerror(errno));
		}

		// printf("write fd=%d chat len:%d writen:%d\n", session->fd, message->len, n);
	}
}


/**
 * 认证
 */
void chat_message_flash_auth(sgc_chat_session_t * session, int len,int type, char * message)
{
	int userid_len, key_len, username_len;
	char * userid,* key, *username;
	char * world;

	PARSE_STR(message, 0, userid_len, userid);
	PARSE_STR(message, userid_len+PKG_LEN_SIZE, username_len, username);
	PARSE_STR(message, userid_len+PKG_LEN_SIZE + username_len + PKG_LEN_SIZE, key_len, key);

	int result[3];
	result[0] = PKG_LEN_SIZE+PKG_TYPE_SIZE;
	result[1] = 500;
	if (strcmp(key, cfg_password) == 0){//普通用户
		sgc_hash_put(sgc_all_userids, userid, session);

		world = CHANNEL_WORLD;
		sgc_user_add_channel(world, session);

		result[2] = 1;
		session->login_type = LOGIN_TYPE_USER;
		session->userid = userid;
		session->username = username;

		sgc_log_debug("login success fd:%d key:%s userid:%s username:%s \n", session->fd, key, userid, username);
	}else if(strcmp(key, cfg_admin_password) == 0){// 管理用户
		sgc_hash_put(sgc_all_userids, userid, session);

		world = CHANNEL_WORLD;
		sgc_user_add_channel(world, session);

		result[2] = 1;
		session->login_type = LOGIN_TYPE_ADMIN;
		session->userid = userid;
		session->username = username;
		sgc_log_debug("login success admin fd:%d key:%s userid:%s username:%s \n", session->fd, key, userid, username);
	}else{
		free(userid);
		free(username);

		result[2] = 2;
		session->login_type = LOGIN_TYPE_NOLOGIN;
		sgc_log_debug("login fail key:%s userid:%s username:%s \n", key, userid, username);
	}

	free(key);

	char buffer[10] = {0};
	memcpy(buffer, &result[0], 4);
	memcpy(buffer+4, &result[1], 2);
	memcpy(buffer+6, &result[2], 4);

	if (writen(session->fd, &buffer,  10) == -1)
	{
		sgc_log_debug("write fail fd=%d %s(%d)\n", session->fd, __FILE__, __LINE__);
	}
}


/**
 * 4，聊天
 */
void chat_message_flash_chat(sgc_chat_session_t * session, int len,int type, char * message)
{
	if (type == 105 && session->login_type != LOGIN_TYPE_ADMIN){
		sgc_log_error("admin error,type=105, fd=%d, type:%d\n", session->fd, session->login_type);
		return;
	}

	int name_len, content_len, str_len, offset, n;
	short sendtype;
	char * name,* content;

	PARSE_STR(message, 0, name_len, name);
	PARSE_STR(message, name_len+ PKG_LEN_SIZE, content_len, content);

	sgc_log_debug("chat fd:%d type:%d, name:%s, content:%s\n",session->fd, type, name, content);

	sgc_chat_message_t data;
	sgc_list_t * list;

	if (type == 103 || type == 105){// 频道聊天
		if (type == 103)
			list = sgc_hash_get(sgc_all_channels, name);
		else
			list = sgc_hash_get(sgc_all_channels, CHANNEL_WORLD);

		if (list != NULL){
			data.len = PKG_LEN_SIZE + PKG_TYPE_SIZE +
					PKG_LEN_SIZE + strlen(session->userid)+
					PKG_LEN_SIZE + strlen(session->username)+
					PKG_LEN_SIZE + strlen(name)+
					PKG_LEN_SIZE + strlen(content);
			data.message = malloc(data.len);
			memset(data.message, 0, data.len);

			if (type == 103)
				sendtype = 506;
			else
				sendtype = 508;

			offset = 0;
			// write length
			str_len = data.len - PKG_LEN_SIZE;
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;
			// write type
			memcpy(data.message+offset, &sendtype, PKG_TYPE_SIZE);
			offset += PKG_TYPE_SIZE;

			//write userid
			str_len = strlen(session->userid);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, session->userid, str_len);
			offset += str_len;

			// write username
			str_len = strlen(session->username);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, session->username, str_len);
			offset += str_len;

			// write channel name
			str_len = strlen(name);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, name, str_len);
			offset += str_len;

			// write content
			str_len = strlen(content);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, content, str_len);

			sgc_log_debug("start send message size:%d\n", list->size);
			sgc_list_foreach(list, &data, send_msg_list_foreach_handler);
			sgc_log_debug("end send message size:%d\n", list->size);
			free(data.message);
		}else{
			// ignore
		}

		// TODO:向其它服务器发送该消息
	}else if (type == 104){// 私聊
		sgc_chat_session_t * session_recv = sgc_hash_get(sgc_all_userids, name);
		if (session_recv != NULL)
		{
			data.len = PKG_LEN_SIZE + PKG_TYPE_SIZE +
								PKG_LEN_SIZE + strlen(session->userid)+
								PKG_LEN_SIZE + strlen(session->username)+
								PKG_LEN_SIZE + strlen(name)+
								PKG_LEN_SIZE + strlen(content);
			data.message = malloc(data.len);

			sendtype = 507;
			offset = 0;
			// write length
			str_len = data.len - PKG_LEN_SIZE;
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;
			// write type
			memcpy(data.message+offset, &sendtype, PKG_TYPE_SIZE);
			offset += PKG_TYPE_SIZE;

			//write userid
			str_len = strlen(session->userid);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, session->userid, str_len);
			offset += str_len;

			// write username
			str_len = strlen(session->username);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, session->username, str_len);
			offset += str_len;

			// write recv userid
			str_len = strlen(name);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, name, str_len);
			offset += str_len;

			// write content
			str_len = strlen(content);
			memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
			offset += PKG_LEN_SIZE;

			memcpy(data.message+offset, content, str_len);

			sgc_dump_char(data.message, data.len);

			if ( (n = writen(session_recv->fd, data.message, data.len)) == -1)
			{
				sgc_log_debug("write fail fd=%d %s(%d)\n", session->fd, __FILE__, __LINE__);
			}

			free(data.message);
		}else{
			// TODO:向该用户所在服务器发送消息
		}
	}

	free(name);
	free(content);
}

/**
 * 3，加入指定频道
 */
void chat_message_flash_addchannel(sgc_chat_session_t * session, int len,int type, char * message)
{
	int name_len, offset, str_len;
	char *name;
	PARSE_STR(message, 0, name_len, name);

	sgc_user_add_channel(name, session);

	// TODO:发送其它服务器 加入频道信息

	sgc_chat_message_t data;
	data.len = PKG_LEN_SIZE + PKG_TYPE_SIZE +
				PKG_LEN_SIZE + strlen(name);
	data.message = malloc(data.len);

	short sendtype = 504;
	offset = 0;
	// write length
	str_len = data.len - PKG_LEN_SIZE;
	memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
	offset += PKG_LEN_SIZE;
	// write type
	memcpy(data.message+offset, &sendtype, PKG_TYPE_SIZE);
	offset += PKG_TYPE_SIZE;

	//write channel name
	str_len = strlen(name);
	memcpy(data.message+offset, &str_len, PKG_LEN_SIZE);
	offset += PKG_LEN_SIZE;

	memcpy(data.message+offset, name, str_len);

	if (writen(session->fd, data.message, data.len) == -1)
	{
		sgc_log_debug("write fail fd=%d %s(%d)\n", session->fd, __FILE__, __LINE__);
	}
	free(data.message);
}

/**
 * 查询好友状态
 */
void chat_message_flash_friend(sgc_chat_session_t * session, int len,int type, char * message)
{
	int arr_friend_len,friend_len, i, pos, pkg_len;
	char * friendid;
	sgc_chat_session_t * friendsession;
	arr_friend_len = *(int *)message;

	sgc_chat_message_t data_up;
	data_up.len = PKG_HEAD_SIZE + PKG_LEN_SIZE + strlen (session->userid);
	data_up.message = malloc(data_up.len);
	short data_up_type = 502;
	int userid_len = strlen(session->userid);
	pkg_len = data_up.len - PKG_LEN_SIZE;
	memcpy(data_up.message, &pkg_len, PKG_LEN_SIZE);
	memcpy(data_up.message+PKG_LEN_SIZE, &data_up_type, PKG_TYPE_SIZE);
	memcpy(data_up.message+PKG_HEAD_SIZE, &userid_len, PKG_LEN_SIZE);
	memcpy(data_up.message+PKG_HEAD_SIZE+PKG_LEN_SIZE, session->userid, userid_len);

	pos = PKG_LEN_SIZE;

	sgc_chat_message_t data_online;
	int online_count = 0, data_online_pos=0;
	short data_online_type= 501;

	data_online_pos = PKG_LEN_SIZE;
	data_online.len = PKG_HEAD_SIZE+PKG_LEN_SIZE;
	data_online.message = malloc(len + PKG_HEAD_SIZE);// 按照最大buffer申请
	memset(data_online.message, 0, data_online.len);

	memcpy(data_online.message+data_online_pos, &data_online_type, PKG_TYPE_SIZE);
	data_online_pos += PKG_TYPE_SIZE;
	data_online_pos += PKG_LEN_SIZE;// count

	for(i=0; i< arr_friend_len; i++){
		PARSE_STR(message, pos, friend_len, friendid);

		sgc_list_push(session->friends, friendid);
		friendsession = sgc_hash_get(sgc_all_userids, friendid);

		// 返回在线好友列表，并通知在线用户，该用户上线了
		if (friendsession != NULL && friendsession->login_type == LOGIN_TYPE_USER){
			data_online.len += PKG_LEN_SIZE + friend_len;
			online_count ++;

			memcpy(data_online.message+data_online_pos, &friend_len, PKG_LEN_SIZE);
			data_online_pos += PKG_LEN_SIZE;
			memcpy(data_online.message+data_online_pos, friendid, friend_len);
			data_online_pos += friend_len;

			if (writen(friendsession->fd, data_up.message, data_up.len) == -1)
			{
				sgc_log_debug("write fail fd=%d, %s(%d)\n", friendsession->fd, __FILE__, __LINE__);
			}
		}

		pos += PKG_LEN_SIZE + friend_len;
	}

	pkg_len = data_online.len - PKG_LEN_SIZE;
	memcpy(data_online.message, &pkg_len, PKG_LEN_SIZE);
	memcpy(data_online.message + PKG_HEAD_SIZE, &online_count, PKG_LEN_SIZE);

	if (writen(session->fd, data_online.message, data_online.len) == -1)
	{
		sgc_log_debug("write fail fd=%d %s(%d)\n", session->fd, __FILE__, __LINE__);
	}

	free(data_up.message);
	free(data_online.message);
}

/**
 * 查看服务器状态
 */
void chat_message_admin_status(sgc_chat_session_t * session, int len,int type, char * message)
{
	if (session->login_type != LOGIN_TYPE_ADMIN){
		sgc_log_error("admin error,type=500, fd=%d, type:%d\n", session->fd, session->login_type);
		return;
	}

	int imlen = 1024;
	char * smessage = (char *)malloc(imlen);
	memset(smessage, 0, imlen);

	snprintf(smessage, imlen, "currentClients:%d\nmaxClients:%d\n",
			session->config->currentclients,
			session->config->maxclients
			);

	// 输出
	imlen = strlen(smessage);
	sgc_chat_message_t data_result;
	data_result.len = PKG_HEAD_SIZE + PKG_LEN_SIZE + strlen (smessage);
	data_result.message = malloc(data_result.len);

	short data_result_type = 600;

	int pkg_len = data_result.len - PKG_LEN_SIZE;
	memcpy(data_result.message, &pkg_len, PKG_LEN_SIZE);
	memcpy(data_result.message+PKG_LEN_SIZE, &data_result_type, PKG_TYPE_SIZE);
	memcpy(data_result.message+PKG_HEAD_SIZE, &imlen, PKG_LEN_SIZE);
	memcpy(data_result.message+PKG_HEAD_SIZE+PKG_LEN_SIZE, smessage, imlen);

	if (writen(session->fd, data_result.message, data_result.len) == -1)
	{
		sgc_log_debug("write fail fd=%d %s(%d)\n", session->fd, __FILE__, __LINE__);
	}

	free(smessage);
	free(data_result.message);
}
